﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TaskDemo
{
    // 异步任务的超时机制
    public class Demo3
    {
        // Thread 的超时机制
        public void ThreadDemo1()
        {
            var thread = new Thread(Foo);
            thread.Start();
            // 表示当前异步任务是否完成
            if (!thread.Join(2000))
            {
                // 超过两秒直接打断取消
                thread.Interrupt();
            }

            void Foo()
            {
                try
                {
                    Console.WriteLine("Foo start...");
                    Thread.Sleep(3000);
                    Console.WriteLine("Foo end...");
                }
                catch(ThreadInterruptedException e)
                {
                    Console.WriteLine($"Foo interrupted:{e}");
                }
                
            }
        }

        // 异步的超时机制
        public async void TaskDemo2()
        {
            var cts = new CancellationTokenSource();
            var fooTask = FooAsync(cts.Token);
            var completedTask = Task.WhenAny(fooTask, Task.Delay(2000));
            if(completedTask != fooTask)
            {
                cts.Cancel();
                await fooTask;
                Console.WriteLine("FooAsync Timout...");
            }

            async Task FooAsync(CancellationToken token)
            {
                try
                {
                    Console.WriteLine("FooAsync start...");
                    await Task.Delay(5000,token);
                    Console.WriteLine("FooAsync end...");
                }
                catch (OperationCanceledException e)
                {
                    Console.WriteLine($"FooAsync interrupted:{e}");
                }
                finally
                {
                    cts.Dispose();
                }
            }
        }

        // dotnet6的异步超时机制
        public async void TaskDemo3()
        {
            var cts = new CancellationTokenSource();
            try
            {
                await FooAsync(cts.Token).WaitAsync(TimeSpan.FromSeconds(2));
                Console.WriteLine("Success!");
            }
            catch (TimeoutException)
            {
                cts.Cancel();
                Console.WriteLine("Timeout!");
            }

            async Task FooAsync(CancellationToken token)
            {
                try
                {
                    Console.WriteLine("FooAsync start...");
                    await Task.Delay(5000, token);
                    Console.WriteLine("FooAsync end...");
                }
                catch (OperationCanceledException e)
                {
                    Console.WriteLine($"FooAsync interrupted:{e}");
                }
                finally
                {
                    cts.Dispose();
                }
            }
        }

    }

    static class AsyncExtensions
    {
        public static async Task<TResult> TimeoutAfter<TResult>(this Task<TResult> task,TimeSpan timeout)
        {
            using var cts = new CancellationTokenSource();
            var completedTask = await Task.WhenAny(task, Task.Delay(timeout, cts.Token));
            if(completedTask != task)
            {
                cts.Cancel();
                throw new TimeoutException();
            }
            return await task;
        }
    }
}
